
#pragma once

#include "base.h"

namespace cgen {
namespace internal {


// A class that controls whether allocation is allowed.  This is for
// the C++ heap only!
class NativeAllocationChecker {
 public:
  typedef enum { ALLOW, DISALLOW } NativeAllocationAllowed;
  explicit inline NativeAllocationChecker(NativeAllocationAllowed allowed)
      : allowed_(allowed) {
#ifdef DEBUG
    if (allowed == DISALLOW) {
      allocation_disallowed_++;
    }
#endif
  }
  ~NativeAllocationChecker() {
#ifdef DEBUG
    if (allowed_ == DISALLOW) {
      allocation_disallowed_--;
    }
#endif
    ASSERT(allocation_disallowed_ >= 0);
  }
  static inline bool allocation_allowed() {
    return allocation_disallowed_ == 0;
  }
 private:
  // This static counter ensures that NativeAllocationCheckers can be nested.
  static int allocation_disallowed_;
  // This flag applies to this particular instance.
  NativeAllocationAllowed allowed_;
};


// Superclass for classes managed with new & delete.
class Malloced {
public:
    void* operator new(size_t size) { return New(size); }
    void  operator delete(void* p) { Delete(p); }

    static void FatalProcessOutOfMemory();
    static void* New(size_t size);
    static void Delete(void* p);
};

// Superclass for classes only using statics.
class AllStatic {
#ifdef DEBUG
 public:
  void* operator new(size_t size);
  void operator delete(void* p);
#endif
};

// A macro is used for defining the base class used for embedded instances.
// The reason is some compilers allocate a minimum of one word for the
// superclass. The macro prevents the use of new & delete in debug mode.
// In release mode we are not willing to pay this overhead.

#ifdef DEBUG
// Superclass for classes with instances allocated inside stack
// activations or inside other objects.
class Embedded
{
public:
    void* operator new(size_t size);
    void  operator delete(void* p);
};
//#define BASE_EMBEDDED : public cgen::internal::Embedded
#define BASE_EMBEDDED : public Embedded
#else
#define BASE_EMBEDDED
#endif


template <typename T>
static T * NewArray(size_t size)
{
    ASSERT(NativeAllocationChecker::allocation_allowed());
    T* result = new T[size];
    if (result == NULL)
    {
        Malloced::FatalProcessOutOfMemory();
    }

    return result;
}


template <typename T>
static void DeleteArray(T * array)
{
    delete[] array;
}


}} // namespace cgen::internal
